<html>
<head>
  <title>13.职责链（Chain Of Responsibility）模式</title>
  <basefont face="微软雅黑" size="2" />
  <meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
  <meta name="exporter-version" content="YXBJ Windows/602628 (zh-CN, DDL); Windows/10.0.0 (Win64); EDAMVersion=V2;"/>
  <style>
    body, td {
      font-family: 微软雅黑;
      font-size: 10pt;
    }
  </style>
</head>
<body>
<a name="23448"/>
<h1>13.职责链（Chain Of Responsibility）模式</h1>
<div>
<table bgcolor="#D4DDE5" border="0">
<tr><td><b>创建时间：</b></td><td><i>2020/7/12 11:05</i></td></tr>
<tr><td><b>更新时间：</b></td><td><i>2021/3/11 0:04</i></td></tr>
<tr><td><b>作者：</b></td><td><i>Long Life Student</i></td></tr>
</table>
</div>
<br/>

<div>
<span><div><div><span style="font-size: 14pt; font-weight: bold;">一、基本描述</span></div><ul><li><div>使多个对象都有机会处理请求，从而避免请求的发送者和接受者之间的耦合关系。将这些对象连成一条链，并沿着这条链传递该请求，直到有一个对象处理它为止。</div></li><li><div>这一模式的想法是，给多个对象处理一个请求的机会，从而解耦发送者和接收者，该请求沿对象链传递直至其中一个对象处理它。</div></li><li><div>从第一个对象开始，链中收到请求的对象要么亲自处理它，要么转发给链中的下一个候选者。提交请求的对象并不明确的知道哪一个对象将会处理它——该请求有一个隐式的接收者。</div></li><li><div>职责链中，发出请求的客户端并不知道当中的哪一个对象最终处理这个请求，这样系统的更改可以在不影响客户端的情况下动态的重新组织和分配责任。</div></li><li><div>职责链使得接收者和发送者都没有对方的明确信息，且链中的对象自己也并不知道链的结构，结果是职责链可简化对象的相互连接，它们仅需保持一个指向其后继者的引用，而不需保持它所有的候选接收者的引用。</div></li><li><div>可以随时的增进或修改处理一个请求的结构，增强了给对象指派职责的灵活性。</div></li><li><div>一个请求极有可能到了链的末端都得不到处理，或者因为没有正确配置而得不到处理。</div></li><li><div>职责链实现的两个重点：1）设置后继者；2）对于每个请求，做出判断，是处理请求，还是转给后继者处理。</div></li><li><div>职责链模式的重点在“链”上，由一条链去处理相似的请求，在链中决定谁来处理这个请求，并返回相应的结果。</div></li><li><div>职责链的核心在于抽象处理者类（Handler）的设计。</div></li><li><div>职责链模式并不创建职责链，职责链的创建工作必须由系统的其他部分来完成。</div></li><li><div>职责链模式可分为纯职责链模式和不纯的职责链模式两种：</div></li></ul><div style="margin-left: 40px;">1）纯职责链：要求一个具体处理者对象只能在两个行为中选择一个：要么承担全部责任，要么将职责推给下家，不允许出现某一个具体处理者对象在承担了一部分或全部责任，要么将责任推给下家不允许出现某一个具体处理者对象在承担了一部分或全部责任后又将责任向下传递的情况。</div><div style="margin-left: 120px;">而且在纯职责链模式中，要求一个请求必须被某一个处理者对象所接收，不能出现某个请求未被任何一个处理者对象处理的情况。</div><div style="margin-left: 40px;">2）不纯职责链：允许某个请求被一个具体处理者部分处理后再向下传递，或者一个具体处理者处理完某个请求后其后继处理者可以继续处理该请求，而且一个请求可以最终不被任何处理者对象接收。</div><div style="margin-left: 40px;">3) 在责任链中一个请求发送到链中后，前一节点消费部分信息，然后交由后续节点继续处理，最终可以有处理结果，也可以没有处理结果，可以不用理会什么纯的、不纯的责任链模式。</div><ul><li><div>在实际应用中，一般会有一个封装类对责任链模式进行封装，替代Client类，直接返回链中的第一个处理者，具体链的设置不需要高层次的模块关系。（也就是说有一个单独的类来封装整个链，设置下一个节点，Client主要与这个类打交道）</div></li><li><div>每个ConcreteHandler类只要关注自己的业务逻辑即可，至于什么事要自己处理，让父类去决定，也即父类实现了请求传递的功能，子类实现请求的处理，符合单一职责原则，各个实现类只完成一个动作或逻辑，也即只有一个原因引起的改变。</div></li><li><div>责任链屏蔽了请求的处理过程，发起一个请求到底是谁处理的，不需关心，只要把请求抛给责任链的第一个处理者，最终会返回一个处理结果（当然也可以不做任何处理），作为请求者可以不用知道到底需要谁来处理的，这是责任链的核心。</div></li><li><div>发出请求的客户端并不知道链上的哪一个对象最终处理这一请求，这使得系统可以在不影响客户端的情况下动态重组链和分配责任。</div></li><li><div>职责链模式并不创建职责链，职责链的创建工作必须由系统其它部分来完成。</div></li><li><div>当你想要让一个以上的对象有机会能够处理某个请求的时候，就使用责任链模式。</div></li></ul><div><span style="font-size: 14pt; font-weight: bold;">二、图例</span></div><div style="text-align: center;"><img src="13.职责链（Chain Of Responsibility）模式_files/Image.png" type="image/png" data-filename="Image.png" width="513"/></div><div style="text-align: center;">类图</div><div style="text-align: center;"><img src="13.职责链（Chain Of Responsibility）模式_files/Image [1].png" type="image/png" data-filename="Image.png" width="639"/></div><div style="text-align: center;">对象图</div><ul><li><div>Handler：定义一个处理请求的接口；（可选）实现后继链。职责链的核心在于引入了一个抽象处理者。</div></li><li><div>ConcreteHandler：处理它所负责的请求。可访问它的后继者。如果可处理该请求，就处理之；否则将该请求转发给它的后继者。</div></li><li><div>Client：向链上的具体处理者（ConcreteHandler）对象提交请求。</div></li></ul><div><span style="font-size: 14pt; font-weight: bold;">三、优缺点</span></div><div><span style="font-weight: bold;">优点</span></div><ul><li><div><span style="font-weight: bold;">降低耦合度</span>：将请求和处理分开，该模式使得一个对象无需知道是其他哪一个对象处理其请求。对象仅需要知道该请求会被“正确”地处理。接收者和发送者都没有对方的明确信息，且链中的对象不需要知道链的结构。结果是，职责链可简化对象的相互连接。它们仅需要保持一个指向其后继的引用，而不需要保持它所有的候选接收者的引用。</div></li><li><div><span style="font-weight: bold;">增强了给对象指派职责的灵活性</span>：当在对象中分派职责时，职责链给你更多的灵活性。你可以通过在运行时对该链进行动态的增加或修改来增加或改变处理一个请求的那些职责。你可以将这种机制与静态的特例化的处理对象的继承机制结合起来使用。</div></li><li><div>请求处理对象仅需维持一个指向其后继者的引用，而不需要维持它对所有的候选处理者的引用，可简化对象的相互连接。</div></li><li><div>在系统中增加一个新的具体请求处理者时无需修改原有系统的代码，只需在客户端重新建链即可，符合“开闭原则”。</div></li><li><div>通过改变链内的成员或调动他们的次序，允许你动态的新增或者删除责任。</div></li></ul><div><span style="font-weight: bold;">缺点</span></div><ul><li><div><span style="font-weight: bold;">不保证被接受</span>：既然一个请求没有明确的接收者，那么就不能保证它一定会被处理——该请求可能一直到链的末端都得不到处理。一个请求也可能因该链没有被正确配置而得不到处理。</div></li><li><div><span style="font-weight: bold;">性能问题</span>：每个请求都从链头遍历到链尾，特别链比较长的时候，性能是一个非常大的问题。</div></li><li><div><span style="font-weight: bold;">调试不方便</span>：特别是链条较长，环节较多的时候，由于采用了类似递归的方式，调试的时候逻辑可能比较复杂。可能不容易观察运行时的特征，有碍于除错。</div></li></ul><div><span style="font-size: 14pt; font-weight: bold;">四、个人理解</span></div><ul><li><div>发送一个请求到链中，链上的对象依次接收请求，如果能处理就处理，不能处理就向下传递这个请求，直到链结束或请求被处理。</div></li></ul><div><br clear="none"/></div></div><div><br/></div></span>
</div></body></html> 